﻿//     Copyright (c) Microsoft Corporation.  All rights reserved.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Xml;
using System.Xml.Linq;
using Microsoft.Gateway.Utils;
using Microsoft.WindowsAzure.ServiceRuntime;

namespace ServiceConfigurationHandler
{
    class Program
    {
        const string ConfigSettingConfigLocation    = "ConfigLocation";
        const string ScheduledTaskName              = "RulesConfigurator";
        const string TaskConfigurationTool          = "schtasks.exe";

        static int Main(string[] args)
        {
            try
            {
                AzureUtils.AddAzureDiagnosticsListener();
                Trace.TraceInformation("Service configuration change handler (version: {0}). Starting...", Assembly.GetEntryAssembly().GetName().Version);
                RoleEnvironment.Changed += RoleEnvironment_Changed;
                Trace.TraceInformation("Waiting...");
                Thread.Sleep(-1);
                return 0;
            }
            catch (Exception ex)
            {
                Console.WriteLine("Failed to initialize: {0}", ex);
                return 1;
            }
        }

        static void RoleEnvironment_Changed(object sender, RoleEnvironmentChangedEventArgs e)
        {
            var configChange = e.Changes
                .OfType<RoleEnvironmentConfigurationSettingChange>()
                .FirstOrDefault(change => String.Equals(change.ConfigurationSettingName, ConfigSettingConfigLocation, StringComparison.OrdinalIgnoreCase));
            if (configChange != null)
            {
                string newConfigValue = RoleEnvironment.GetConfigurationSettingValue(configChange.ConfigurationSettingName);
                Trace.TraceInformation("Service configuration has changed. New value is: {0}", newConfigValue);
                ApplyServiceConfigurationChange(newConfigValue);
            }
        }

        static void ApplyServiceConfigurationChange(string newConfigValue)
        {
            var taskProcInfo = new ProcessStartInfo()
            {
                FileName = TaskConfigurationTool,
                Arguments = String.Format("/query /xml /tn {0}", ScheduledTaskName),
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                UseShellExecute = false,
            };
            try
            {
                using (var taskListProcess = Process.Start(taskProcInfo))
                {
                    if (taskListProcess.WaitForExit(5000) && taskListProcess.ExitCode == 0)
                    {
                        var outputReader = taskListProcess.StandardOutput;
                        var taskInfo = XDocument.Load(outputReader);
                        XNamespace xmlns = "http://schemas.microsoft.com/windows/2004/02/mit/task";
                        var argsElement = taskInfo.Descendants(xmlns + "Arguments").FirstOrDefault();
                        if (argsElement != null)
                        {
                            argsElement.Value = '"' + newConfigValue + '"';
                            string taskDefinitionFile = Path.GetTempFileName();
                            var xmlWriterSettings = new XmlWriterSettings()
                            {
                                Encoding = Encoding.ASCII,
                                CloseOutput = true,
                                Indent = true,
                                NewLineHandling = NewLineHandling.Entitize,
                                OmitXmlDeclaration = true,
                            };
                            using (var taskFileWriter = XmlWriter.Create(taskDefinitionFile, xmlWriterSettings))
                            {
                                taskInfo.WriteTo(taskFileWriter);
                            }
                            taskProcInfo.Arguments = String.Format("/create /f /xml \"{0}\" /tn {1}", taskDefinitionFile, ScheduledTaskName);
                            using (var createTaskProcess = Process.Start(taskProcInfo))
                            {
                                if (createTaskProcess.WaitForExit(5000))
                                {
                                    if (createTaskProcess.ExitCode != 0)
                                    {
                                        Trace.TraceWarning("Failed to apply new service configuration. Error updating scheduled task: {0}", 
                                            createTaskProcess.StandardError.ReadToEnd());
                                    }
                                    else
                                    {
                                        Trace.TraceInformation("Configuration change successfully applied.");
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        Trace.TraceWarning("Failed to apply new service configuration. Error obtaining scheduled task details: {0}", 
                            taskListProcess.StandardError.ReadToEnd());
                    }
                }
            }
            catch (Exception ex)
            {
                Trace.TraceWarning("Failed to apply new service configuration. Exception: {0}", ex);
            }
        }
    }
}
